#pragma once
#include "../qbtools.h"
#include <functional>
#include <qbprotocol/include/message.h>
#include <qbprotocol/include/SSMsgStruct.h>
#include <qbprotocol/include/rdProto.h>
#include <set>
#include <vector>
#include "RequestNotifier.h"

typedef std::function<void(qb::proto::Message&, qb::SSRequestMsg*)> WrapReqFunc;

class MessageReceiver;
/// <summary>
/// 消息发送封装类
/// </summary>
class S_TOOL_EXPORT MessagePoster
{
public:
	/// <summary>
	/// 发送原始数据流
	/// </summary>
	/// <param name="connect_id"></param>
	MessagePoster(int connect_id);

	/// <summary>
	/// 发送SSRequestMsg
	/// </summary>
	/// <param name="connect_id"></param>
	/// <param name="req">发送的消息体</param>
	/// <param name="func">该消息体封装成protoMessage的函数</param>
	MessagePoster(int connect_id, qb::SSRequestMsg* req, WrapReqFunc func);
	
	/// <summary>
	/// 发送特定消息，refer CLoginGwVerifyTask::SendClientInfo
	/// </summary>
	/// <param name="pr">接收该消息返回数据的对象</param>
	/// <returns>成功：消息号；失败-1 </returns>
	int send(MessageReceiver* pr = nullptr);

	/// <summary>
	/// 发送原始数据，refer SSUserAccountManager::requestSystime
	/// </summary>
	/// <param name="buf">The buf.</param>
	/// <param name="iLen">Length of the i.</param>
	/// <param name="msgType">Type of the MSG.</param>
	/// <returns>发送字节数</returns>
	int send(char* buf, int iLen, int msgType = E_FID_SERVER_QPID);

private:
	int m_connect_id = 0;
	qb::SSRequestMsg* m_req = nullptr;
	WrapReqFunc	m_reqWrapFunc = nullptr;
};

/// <summary>
/// 消息接收封装类，要接受消息的widget继承此类
/// </summary>
class S_TOOL_EXPORT MessageReceiver
{
public:
	MessageReceiver() = default;
	virtual ~MessageReceiver();

	/// <summary>
	/// 无需手动调用
	/// </summary>
	/// <param name="v"></param>
	void addReqs(int v) { m_reqs.insert(v); }

	/// <summary>
	/// 注册需要接收的推送消息
	/// </summary>
	/// <param name="pmi">推送消息信息：消息号，参数，填充参数的函数</param>
	/// <param name="req">注册推送的消息</param>
	/// <param name="fun">封装消息到protoMessage的函数</param>
	void registPush(const PushMsgInfo& pmi, qb::SSRequestMsg* req = nullptr, WrapReqFunc fun = nullptr);

	void unRegistPush(const PushMsgInfo& pmi, qb::SSRequestMsg* req = nullptr, WrapReqFunc fun = nullptr);

	/// <summary>
	/// 数据接受回调函数，注意:此函数在非UI线程！不要在此函数内做耗时操作!
	/// </summary>
	/// <param name="msg">返回数据</param>
	virtual void onDataArrived(const qb::SSAckMsg& msg) = 0;

private:
	std::set<int>	m_reqs;
	std::vector<PushMsgInfo>	m_pushes;
};
